#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "member.h"
#include "common.h"


#define MEMBER_INFO_FILE "./data/member_info.data"  // 会员信息文件路径
#define MEMBER_ID_BASE 100001  // 会员 ID 起始值


void print_member_info(const member_info* mi);  // 会员信息
void member_mod(void);  // 修改会员信息内容


// 获取会员 ID
static unsigned int get_new_mid(void)
{
	member_info mi;  // 会员信息结构体变量
	unsigned int mid;   // 新会员 ID

	FILE* fp = fopen(MEMBER_INFO_FILE, "rb");  // 以二进制只读方式打开会员信息文件

	if(fp == NULL)
	{
		return MEMBER_ID_BASE;
	}

	fseek(fp, -sizeof(mi), SEEK_END);  // 将文件指针移动到文件末尾前一个会员信息记录的位置

	if(fread(&mi, sizeof(mi), 1, fp) == 1)  // 返回值为实际成功读取的个数，会小于等于第三个参数，而第三个参数时实际想要从文件中读取的个数
	{
		mid = mi.mid + 1;  // 新会员 ID 为最后一个会员 ID 加 1
	}
	else
	{
		mid = MEMBER_ID_BASE;  // 如果读取失败，说明文件为空，新会员 ID 为起始值
	}

	fclose(fp);  // 关闭文件

	return mid;  // 返回新会员 ID
}


// 注册会员
void member_reg(void)
{
	member_info mi;  // 会员信息结构体变量

	printf("******************************************\n");
	printf("请按照如下提示输入会员信息:\n\n");

	// 卡号输入验证
	while(1)
	{
		printf("卡号:");
		scanf("%s", mi.card_num);
		// 清空输入缓冲区
        while (getchar() != '\n');  // 读取并丢弃直到换行符

		
		if(strlen(mi.card_num) == 10)
		{
			break; // 卡号长度正确，退出循环
		}
		else
		{
			printf("卡号输入有误！请重新输入！\n\n");
		}
	}

	printf("姓名:");
	scanf("%s", mi.name);
	// 清空输入缓冲区
    while (getchar() != '\n');  // 读取并丢弃直到换行符


	printf("性别(1-女,2-男):");
	scanf("%d", (int*)&mi.s);
	// 清空输入缓冲区
    while (getchar() != '\n');  // 读取并丢弃直到换行符


	// 卡号输入验证
	while(1)
	{
		printf("手机号:");
		scanf("%s", mi.phone);
		// 清空输入缓冲区
        while (getchar() != '\n');  // 读取并丢弃直到换行符

		if(strlen(mi.phone) == 11)
		{
			break; // 手机号长度正确，退出循环
		}
		else
		{
			printf("输入有误！请重新输入！\n\n");
		}
	}
	printf("会员类型:(1-次卡,2-月卡,3-年卡):");
	scanf("%d", (int*)&mi.mt);
	// 清空输入缓冲区
    while (getchar() != '\n');  // 读取并丢弃直到换行符

	mi.last_swipe_time = 0;

	if(mi.mt == cika)
	{
		printf("请输入剩余次数:");
		scanf("%d", &mi.remain_cnt);
		// 清空输入缓冲区
        while (getchar() != '\n');  // 读取并丢弃直到换行符

	}

	mi.reg_time = time(NULL);  // 获取当前时间作为注册时间

	if(mi.mt == yueka)  // 月卡
		mi.expire_time = mi.reg_time + 30 * 24 * 60 * 60;  // 到期时间为注册时间加 30 天
	else
		mi.expire_time = mi.reg_time + 365 * 24 * 60 * 60;  // 到期时间为注册时间加 365 天

	mi.mid = get_new_mid();  // 获取新会员 ID
	mi.delete_state = 0;  // 设置删除状态为未删除

	FILE* fp = fopen(MEMBER_INFO_FILE, "ab");  // 以二进制追加方式打开会员信息文件

	if(fp == NULL)
	{
		perror("\n             会员注册失败！\n");
		return;
	}

	fwrite(&mi, sizeof(mi), 1, fp);  // 将会员信息写入文件

	fclose(fp);  // 关闭文件

	printf("\n             会员注册成功！\n");

	press_any_key();
}


// 删除会员
void member_del(void)
{
	char num[50];
	member_info mi;  // 会员信息结构体变量
	// 清空输入缓冲区
    while (getchar() != '\n');  // 读取并丢弃直到换行符


	printf("******************************************\n");
	printf("请输入要注销的会员的卡号/会员ID/手机号:");
	scanf("%s", num);
	// 清空输入缓冲区
    while (getchar() != '\n');  // 读取并丢弃直到换行符


	FILE* fp = fopen(MEMBER_INFO_FILE, "r+");  // 以读写方式打开会员信息文件

	while(fread(&mi, sizeof(mi), 1, fp) == 1)  // 查找会员
	{
		if(strcmp(num, mi.card_num) == 0 || strcmp(num, mi.phone) == 0 || atol(num) == mi.mid)
		{
			break;
		}
	}

	if(feof(fp))  // 未找到会员
	{
		printf("******************************************\n");
		printf("很抱歉！不存在此会员，注销失败！\n");
		press_any_key();
		return;
	}
	else
	{
		char select;

		if(mi.delete_state == 1)  // 已经注销
		{
			printf("此卡已注销，无法再次注销！\n");
			printf("******************************************\n");
			fclose(fp);
			press_any_key();
			return;
		}
		
		printf("******************************************\n");
		printf("要注销的会员信息如下:\n\n");
		print_member_info(&mi);  // 打印会员信息

		printf("******************************************\n");
		printf("是否确定要注销此会员(Y/N):");
		select = getchar();
		// 清空输入缓冲区
        while (getchar() != '\n');  // 读取并丢弃直到换行符

		if(select == 'Y' || select == 'y')  // 确认注销
		{
			mi.delete_state = 1;  // 设置删除状态为已删除
			
			fseek(fp, -sizeof(mi), SEEK_CUR);  // 将文件指针移动到当前会员信息记录的起始位置

			fwrite(&mi, sizeof(mi), 1, fp);  // 更新会员信息

			printf("             该会员已注销！\n");
			printf("******************************************\n");
		}
	}

	fclose(fp);  // 关闭文件

	press_any_key();
} 


// 修改会员信息
void member_modify(void)
{
    char num[50];
    member_info mi;  // 会员信息结构体变量
    long pos = 0;
    int found = 0;

    printf("******************************************\n");
    printf("请输入要修改的会员的卡号/会员ID/手机号:");
    scanf("%s", num);
    // 清空输入缓冲区
    while (getchar() != '\n');  // 读取并丢弃直到换行符

    FILE* fp = fopen(MEMBER_INFO_FILE, "r+b");  // 以读写方式打开会员信息文件
    if(fp == NULL)
    {
        printf("文件打开失败！\n");
        printf("******************************************\n");
		press_any_key();
        return;
    }

    // 查找会员
    while(fread(&mi, sizeof(mi), 1, fp) == 1)
    {
        if(strcmp(num, mi.card_num) == 0 || strcmp(num, mi.phone) == 0 || atol(num) == mi.mid)  // 找到会员
        {
            found = 1;  // 标记为找到
            pos = ftell(fp) - sizeof(mi);  // 获取当前文件指针位置
            break;
        }
    }

    if(!found)  // 未找到会员
    {
        printf("******************************************\n");
        printf("很抱歉！不存在此会员，修改失败！\n");
        fclose(fp);
		press_any_key();
        return;
    }

    if(mi.delete_state == 1)  // 已经注销
    {
        printf("此卡已注销，无法修改！\n");
        printf("******************************************\n");
        fclose(fp);
		press_any_key();
        return;
    }

	int choice;  // 用户选择
	char continue_modify;  // 是否继续修改标志

    do
    {
    	printf("******************************************\n");
    	printf("当前会员信息如下:\n\n");
    	print_member_info(&mi);  // 打印会员信息

		member_mod();  // 显示修改选项

    	int choice;
    	scanf("%d", &choice);
    	// 清空输入缓冲区
        while (getchar() != '\n');  // 读取并丢弃直到换行符

    	switch(choice)
    	{
        	case 1: // 修改姓名
            	printf("请输入新的姓名:");
            	scanf("%s", mi.name);
				// 清空输入缓冲区
        		while (getchar() != '\n');  // 读取并丢弃直到换行符
            	printf("姓名修改成功！\n");
            	break;
            
       		case 2: // 修改性别
           		printf("请输入新的性别(1-女,2-男):");
            	scanf("%d", (int*)&mi.s);
				// 清空输入缓冲区
        		while (getchar() != '\n');  // 读取并丢弃直到换行符
            	printf("性别修改成功！\n");
            	break;
            
        	case 3: // 修改手机号
				while(1)
				{
					printf("手机号:");
					scanf("%s", mi.phone);
					// 清空输入缓冲区
        			while (getchar() != '\n');  // 读取并丢弃直到换行符

					if(strlen(mi.phone) == 11)
					{
						break; // 手机号长度正确，退出循环
					}
					else
					{
						printf("输入有误！请重新输入！\n\n");
					}
				}
            	printf("手机号修改成功！\n");
            	break;
            
        	case 4: // 修改会员类型
            	printf("请输入新的会员类型(1-次卡,2-月卡,3-年卡):");
            	scanf("%d", (int*)&mi.mt);
				// 清空输入缓冲区
        	    while (getchar() != '\n');  // 读取并丢弃直到换行符
            
            	// 如果改为次卡，需要设置剩余次数
            	if(mi.mt == cika)
            	{
                	printf("请输入剩余次数:");
                	scanf("%d", &mi.remain_cnt);
					// 清空输入缓冲区
                    while (getchar() != '\n');  // 读取并丢弃直到换行符
            	}
            
            	// 更新到期时间
            	if(mi.mt == yueka)
                	mi.expire_time = mi.reg_time + 30 * 24 * 60 * 60;  // 月卡
            	else if(mi.mt == nianka)
                	mi.expire_time = mi.reg_time + 365 * 24 * 60 * 60;  // 年卡
                
            	printf("会员类型修改成功！\n");
            	break;
            
        	case 5: // 修改剩余次数
            	if(mi.mt != cika)
            	{
              	  printf("只有次卡会员才能修改剩余次数！\n");
              	  break;
           		}
            	printf("请输入新的剩余次数:");
            	scanf("%d", &mi.remain_cnt);
				// 清空输入缓冲区
        while (getchar() != '\n');  // 读取并丢弃直到换行符
            	printf("剩余次数修改成功！\n");
            	break;

        	case 6: // 退出
            	printf("                已退出！\n");
            	fclose(fp);
            	return;
            
        	default:
            	printf("无效的选择！\n");
            	fclose(fp);
            	return;
    	}

    	// 更新会员信息
    	fseek(fp, pos, SEEK_SET);  // 将文件指针移动到该会员信息记录的起始位置
    	fwrite(&mi, sizeof(mi), 1, fp);  // 写入更新后的会员信息
    
    	printf("******************************************\n");
    	printf("会员信息修改成功！\n");

		// 询问是否继续修改
        printf("是否继续修改此会员信息?(Y/N):");
        continue_modify = getchar();  // 获取用户输入
        // 清空输入缓冲区
        while (getchar() != '\n');  // 读取并丢弃直到换行符

	} while(continue_modify == 'Y' || continue_modify == 'y');  // 如果用户选择继续修改，则重复循环

    fclose(fp);

	press_any_key();
}


void member_mod(void)  // 修改会员信息内容
{
	printf("******************************************\n");
    printf("请选择要修改的信息:\n");
    printf("1. 姓名\n");
    printf("2. 性别\n");
    printf("3. 手机号\n");
    printf("4. 会员类型\n");
    printf("5. 剩余次数(仅次卡)\n");
    printf("6. 退出\n");
    printf("请选择(1-6):");
}


// 查询会员信息
void member_show(void)
{
	member_info mi;  // 会员信息结构体变量
	char card_num[11];
	// system("clear");  // 清屏

	printf("******************************************\n");
	printf("会员请刷卡！(卡号、手机号、会员ID任选其一)\n");
	scanf("%s", card_num);
	// 清空输入缓冲区
    while (getchar() != '\n');  // 释放输入缓冲区的内容，否则会影响下次 getchar 的调用

	FILE* fp = fopen(MEMBER_INFO_FILE, "rb");  // 以二进制只读方式打开会员信息文件
	
	if(fp == NULL)
	{
		printf("很抱歉，该卡未注册，请联系工作人员处理！\n");
		printf("******************************************\n");
		press_any_key();
		return;
	}

	while(fread(&mi, sizeof(mi), 1, fp) == 1)  // 查找会员
	{
		if(strcmp(card_num, mi.card_num) == 0 || strcmp(card_num, mi.phone) == 0 || atol(card_num) == mi.mid)  // 找到会员
		{
			break;
		}
	}

	if(feof(fp))  // 未找到会员
	{
		printf("很抱歉，该卡未注册，请联系工作人员处理！\n");
		printf("******************************************\n");
		press_any_key();
		return;
	}
	else
	{
		if(mi.delete_state == 1)  // 已经注销
		{
			printf("此卡已注销，请联系工作人员处理！\n");
			printf("******************************************\n");
			press_any_key();
			return;
		}
		else
		{
			printf("******************************************\n");
			printf("尊贵的会员，您的个人信息如下：\n\n");
			print_member_info(&mi);  // 打印会员信息
		}
	}
	fclose(fp);

	press_any_key();
}


// 会员信息
void print_member_info(const member_info* mi) // 参数为会员信息结构体指针
{

	printf("卡号:%s\n", mi->card_num);
	printf("会员ID:%u\n", mi->mid);
	printf("姓名:%s\n", mi->name);
	printf("性别:%s\n", mi->s == female ? "女" : "男");
	printf("手机号:%s\n", mi->phone);

	printf("会员类型:");
	if(mi->mt == cika)
	{
		printf("次卡\n剩余次数:%d\n", mi->remain_cnt);
		return;
	}
	else if(mi->mt == yueka)
	{
		printf("月卡\n");
	}
	else if(mi->mt == nianka)
	{
		printf("年卡\n");
	}

	struct tm* dt;  // 时间结构体指针

	dt = localtime(&mi->expire_time);   // 将到期时间转换为本地时间结构体

	printf("该卡的到期时间:%d年%d月%d日 %02d:%02d\n", dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday, dt->tm_hour, dt->tm_min);  

	dt = localtime(&mi->reg_time);  // 将注册时间转换为本地时间结构体

	printf("该卡的注册时间:%d年%d月%d日 %02d:%02d\n", dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday, dt->tm_hour, dt->tm_min);
}


// 刷卡进场
void member_in(void)
{
	// 会员刷卡
	member_info mi;  // 会员信息结构体变量
	char card_num[11];
	int found = 0;
	long pos = 0;  // 记录文件指针位置
	time_t member_in_time = time(NULL);  // 会员进场时间

	printf("******************************************\n");
	printf("请刷卡进场(卡号、手机号、会员ID任选其一)\n");
	scanf("%s", card_num);
	// 清空输入缓冲区
    while (getchar() != '\n');  // 读取并丢弃直到换行符


	FILE* fp = fopen(MEMBER_INFO_FILE, "r+b");  // 以二进制读写方式打开会员信息文件
	if(fp == NULL)
	{
		printf("很抱歉，该卡未注册，请联系工作人员处理！\n");
		printf("******************************************\n");
		press_any_key();
		return;
	}

	
	while(fread(&mi, sizeof(mi), 1, fp) == 1)  // 查找会员
	{
		if(strcmp(card_num, mi.card_num) == 0 || strcmp(card_num, mi.phone) == 0 || atol(card_num) == mi.mid)  // 找到会员
		{
			found = 1;  // 标记为找到
			pos = ftell(fp) - sizeof(mi);  // 获取当前文件指针位置
			break;
		}
	}

	if(feof(fp))  // 未找到会员
	{
		printf("很抱歉，该卡未注册，请联系工作人员处理！\n");
		printf("******************************************\n");
		press_any_key();
		return;
	}

	if(mi.delete_state == 1)  // 已经注销
	{
		printf("此卡已注销，请联系工作人员处理！\n");
		printf("******************************************\n");
		press_any_key();
		return;
	}
	else
	{
		printf("******************************************\n");
		printf("亲爱的会员：%s,欢迎您的到来！\n", mi.name);

		// 会员进场时间
		struct tm* dt = localtime(&member_in_time);  // 将进场时间转换为本地时间结构体
		printf("会员进场时间:%d年%d月%d日 %02d:%02d\n", dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday, dt->tm_hour, dt->tm_min);

		// 检查是否是今天第一次刷卡
   		int should_deduct = 1; // 默认需要扣次数
			
  		if(mi.last_swipe_time != 0) // 如果有上次刷卡记录
		{
    		// 检查是否在同一天
        	struct tm* last_swipe_tm = localtime(&mi.last_swipe_time);
        	if(last_swipe_tm->tm_year == dt->tm_year && last_swipe_tm->tm_mon == dt->tm_mon && last_swipe_tm->tm_mday == dt->tm_mday)
       		{
        		// 同一天内再次刷卡，不扣次数
            	should_deduct = 0;  // 不扣次数
           		printf("今日已刷过卡，本次不扣次数！\n");
       		}
   		}

		// 如果需要扣次数且还有剩余次数
    	if(should_deduct && mi.remain_cnt > 0)  // 扣除一次
    	{
        	mi.remain_cnt--;
        	printf("扣除1次!\n");
    	}
    	else if(should_deduct && mi.remain_cnt <= 0)  // 次数用完
    	{
        	printf("次数已用完，无法进场！\n");
        	fclose(fp);
			press_any_key();
        	return;
    	}
	}
	
	// 更新上次刷卡时间为当前时间
    mi.last_swipe_time = member_in_time;  // 设置上次刷卡时间为当前时间

	// 更新会员信息
	fseek(fp, -sizeof(mi), SEEK_CUR);  // 将文件指针移动到该会员信息记录的起始位置
	fwrite(&mi, sizeof(mi), 1, fp);   // 写入更新后的会员信息
	
	fclose(fp);

	press_any_key();
}


// 刷卡离场
void member_out(void)
{
	// 会员刷卡
	member_info mi;  // 会员信息结构体变量
	char card_num[11];
	int found = 0;

	printf("请刷卡离场(卡号、手机号、会员ID任选其一)\n");
	scanf("%s", card_num);
	// 清空输入缓冲区
    while (getchar() != '\n');  // 读取并丢弃直到换行符


	FILE* fp = fopen(MEMBER_INFO_FILE, "r+b");  // 以二进制读写方式打开会员信息文件
	if(fp == NULL)
	{
		printf("很抱歉，该卡未识别，请联系工作人员处理！\n");
		printf("******************************************\n");
		press_any_key();
		return;
	}

	while(fread(&mi, sizeof(mi), 1, fp) == 1)  // 查找会员
	{
		if(strcmp(card_num, mi.card_num) == 0 || strcmp(card_num, mi.phone) == 0 || atol(card_num) == mi.mid)  // 找到会员
		{
			found = 1;  // 标记为找到
			break;
		}
	}

	if(!found)  // 未找到会员
	{
		printf("很抱歉，该卡未注册，请联系工作人员处理！\n");
		printf("******************************************\n");
		fclose(fp);
		press_any_key();
		return;
	}

	if(mi.delete_state == 1)  // 已经注销
	{
		printf("此卡已注销，请联系工作人员处理！\n");
		printf("******************************************\n");
		press_any_key();
		return;
	}

	if(feof(fp))  // 未找到会员
	{
		printf("很抱歉，该卡未注册，请联系工作人员处理！\n");
		printf("******************************************\n");
		press_any_key();
		return;
	}

	// 会员离场时间
	time_t member_out_time = time(NULL);  // 获取当前时间作为会员离场时间
	struct tm* dt = localtime(&member_out_time);  // 将离场时间转换为本地时间结构体
	printf("会员离场时间:%d年%d月%d日 %02d:%02d\n", dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday, dt->tm_hour, dt->tm_min);

	printf("感谢会员 %s 的光临！欢迎下次再来！\n", mi.name);

	press_any_key();
}